#pragma oncce

#include <iostream>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <unistd.h>
#include "comm.hpp"

#define CREATOR "creator"
#define USER "user"

const std::string path = ".";
const int defaultshmid = -1;
const int defaultprojid = 0x66;
const int defaultsize = 4096;

class shm
{
private:
    void CreateHelper(int flg)
    {
        _shmid = shmget(_key, _size, flg);
        if (_shmid < 0)
        {
            ERR_EXIT("shmget");
        }
        std::cout << "create shm success!" << std::endl;
    }

    void Create()
    {
        CreateHelper(IPC_CREAT | IPC_EXCL | 0666);
    }

    void Get()
    {
        CreateHelper(IPC_CREAT);
    }

    void Attach()
    {
        _add = shmat(_shmid, nullptr, 0);
        if ((long long)_add < 0)
        {
            ERR_EXIT("shmat");
        }
        std::cout << "attach success!" << std::endl;
    }

    void Detach()
    {
        int n = shmdt(_add);
        if (n < 0)
        {
            ERR_EXIT("shmdt");
        }
        std::cout << "detach success!" << std::endl;
    }

    void Destroy()
    {
        Detach();
        int n = shmctl(_shmid, IPC_RMID, nullptr);
        if (n < 0)
        {
            ERR_EXIT("shmctl");
        }
        std::cout << "shmctl success!" << std::endl;
    }

public:
    shm(std::string path, int projid, size_t size, std::string usetype)
        : _size(size), _usetype(usetype), _add(nullptr), _shmid(defaultshmid)
    {
        _key = ftok(path.c_str(), projid);
        if (_key < 0)
        {
            ERR_EXIT("ftok");
        }
        if (_usetype == "creator")
        {
            Create();
        }
        else
        {
            Get();
        }
        Attach();
    }

    void *VirtualAddr()
    {
        return _add;
    }

    ~shm()
    {
        if (_usetype == "creator")
            Destroy();
    }

private:
    key_t _key;
    int _shmid;
    std::string _usetype;
    size_t _size;
    void *_add;
};